package net.xiaohanlin.smartmetric.monitor.jvm;

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import com.codahale.metrics.Gauge;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricSet;

public class GarbageCollectorMetricSet extends AbstractJvmMetric implements MetricSet {

	private static final Pattern WHITESPACE = Pattern.compile("[\\s]+");

	private final List<GarbageCollectorMXBean> garbageCollectors;

	/**
	 * Creates a new set of gauges for all discoverable garbage collectors.
	 */
	public GarbageCollectorMetricSet() {
		this(ManagementFactory.getGarbageCollectorMXBeans());
	}

	/**
	 * Creates a new set of gauges for the given collection of garbage
	 * collectors.
	 *
	 * @param garbageCollectors the garbage collectors
	 */
	public GarbageCollectorMetricSet(Collection<GarbageCollectorMXBean> garbageCollectors) {
		this.garbageCollectors = new ArrayList<GarbageCollectorMXBean>(garbageCollectors);
	}

	private static final String NameFormatter = "jvm_gc_%s_%s";

	@Override
	public Map<String, Metric> getMetrics() {
		final Map<String, Metric> gauges = new HashMap<String, Metric>();
		for (final GarbageCollectorMXBean gc : garbageCollectors) {
			final String name = WHITESPACE.matcher(gc.getName()).replaceAll("-");
			gauges.put(getMetricName(String.format(NameFormatter, name, "count")), new Gauge<Long>() {
				@Override
				public Long getValue() {
					return gc.getCollectionCount();
				}
			});

			gauges.put(getMetricName(String.format(NameFormatter, name, "time")), new Gauge<Long>() {
				@Override
				public Long getValue() {
					return gc.getCollectionTime();
				}
			});
		}
		return Collections.unmodifiableMap(gauges);
	}
}
